/*  
  1. 概念
    在接口、类、函数的时候，不预先定义类型，而是在使用时定义类型
  2. 泛型默认值
    <T = string>
  3. 泛型约束
    <T extends U>
  4. 泛型工具类型：Pick(挑选)、Omit（排除）、Partial（可选）、Required（必填）
  5. 泛型应用：
    1. axios: request<any, Xxx>()
    2. react: useState<Xxx>()
    3. vue3:  ref<Xxx>()  reactive<Xxx>()
*/

// function fn(n: string): string;
// function fn(n: number): number;
// function fn(n: string | number): string | number {
//   return n;
// }

// 定义泛型时，不会指定类型
// <T> 定义泛型参数T, 此时类型不知道
// n: T 参数n个类型也是T
// : T  函数的返回值类型也是T
function fn<T>(n: T): T {
  return n;
}

// 使用时，传入类型（定义类型）
fn<string>("1");

function fn1<T, K, V>(n: T): T {
  return n;
}

fn1<string, number, any>("1");

interface Person<T> {
  name: T;
}

const obj: Person<string> = {
  name: "jack",
};

class Son<T> {
  name: T;
}

// function fn2<T = string>(n: T): T {
//   return n;
// }
// fn2("1");

// 2. 泛型默认值
// T是必选泛型参数
// interface IPerson<T> {
//   name: T;
// }
// T有默认值类型为string，可选泛型参数
interface IPerson<T = string> {
  name: T;
}

const p: IPerson<number> = {
  name: 123,
};

interface ILength {
  length: number;
}

// interface T extends ILength {}

// const t: T = {
//   length: 123
// }
// 3. 泛型约束
function fn3<T extends ILength>(n: T): T {
  console.log(n.length);
  return n;
}

// 4. 泛型工具类型: Pick、Omit、Partial、Required
interface ISku {
  skuName: string;
  skuDesc: string;
  price: number;
  weight?: number;
  skuSaleAttrList?: any;
  skuAttrList: any;
  skuImageList: any;
}

// 从 ISku 类型中挑选 skuName、skuDesc、price 组成一个新的类型
type PickSku = Pick<ISku, "skuName" | "skuDesc" | "price">;

// 从 ISku 类型中排除 skuName、skuDesc、price 属性，由其他属性组成一个新的类型
type OmitSku = Omit<ISku, "skuName" | "skuDesc" | "price">;

// 将 ISku 类型中所有属性变成可选类型
type PartialSku = Partial<ISku>;

// 将 ISku 类型中所有属性变成必选类型
type RequiredSku = Required<ISku>;

type SkuKeys = keyof ISku; // "skuName" | "skuDesc" | "price" | "weight" ...

const key: SkuKeys = "skuName";
